// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef CLOUDAPPSDK_CASDECODER_H
#define CLOUDAPPSDK_CASDECODER_H

#include <unistd.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaFormat.h>
#include "CasVideoUtil.h"
#include "CasVideoEngineCommon.h"

const uint32_t DECODER_SUCCESS = 0;
const uint32_t DECODER_INIT_ERR = 0x01;
const uint32_t DECODER_START_ERR = 0x02;
const uint32_t DECODER_INPUT_ERR = 0x03;
const uint32_t DECODER_OUTPUT_RETRY = 0x04;
const uint32_t DECODER_OUTPUT_ERR = 0x05;
const uint32_t DECODER_SDK_UNSUPPORTED = 0x06;

class CasDecoder {
public:
    /*
     * @fn CasDecoder
     * @brief constructor
     */
    CasDecoder();

    /*
     * @fn CasDecoderder
     * @brief destructor
     */
    ~CasDecoder();

    /*
     * @fn Init
     * @brief to create and configure MediaCodec.
     * @param[in] nativeWindow View to display of (type <tt>ANativeWindow *</tt>)
     * @return errno: DECODER_SUCCESS
     *                DECODER_INIT_ERR
     */
    uint32_t Init(ANativeWindow *nativeWindow, FrameType frameType, int rotationDegrees);

    /*
     * @fn Start
     * @brief to start MediaCodec
     * @return errno: DECODER_SUCCESS
     *                DECODER_START_ERR
     */
    uint32_t Start();

    /*
     * @fn Input
     * @brief to place processing data into InputBuffer, and MediaCodec would
     * fetch it to process asynchronously.
     * @param[in] buf Initial address of processing data of (type <tt>const uint8_t*</tt>)
     * @param[in] len Length of processing data of (type <tt>size_t</tt>)
     * @return errno: DECODER_SUCCESS
     *                DECODER_INPUT_ERR
     */
    uint32_t Input(const uint8_t *buf, const size_t len);

    /*
     * @fn OutputAndDisplay
     * @brief to output processed data into OutputBuffer from MediaCodec,
     * and release OutputBuffer to render for display
     * @return errno: DECODER_SUCCESS
     *                DECODER_OUTPUT_RETRY
     *                DECODER_OUTPUT_ERR
     */
    uint32_t OutputAndDisplay(bool idDisplay);

    /*
     * @fn GetFps
     * @brief to get the realtime fps
     * @return realtime decoded fps
     */
    uint32_t GetFps() const;

    /*
     * @fn Destroy
     * @brief to destroy MediaCodec, and release the resources it possesses.
     */
    void Destroy() noexcept;

private:
    /*
     * @fn CreateMediaCodecFmt
     * @brief to create AMediaFormat for MediaCodec configuration.
     * @param[in] rotation degrees
     * @return AMediaFormat for MediaCodec configuration
     */
    AMediaFormat *CreateMediaCodecFmt(int rotationDegrees) const;

    /*
     * @fn AssembleMemory
     * @brief to append h264 frame bits with the eopic bits
     * @param[in] buf Initial address of processing data of (type <tt>const uint8_t*</tt>)
     * @param[in] len Length of processing data of (type <tt>size_t</tt>)
     * @return pointer to the assembly memory, nullptr when failure
     */
    uint8_t *AssembleMemory(const uint8_t *buf, const size_t len) const;

    /*
     * @fn GetInputBuffer
     * @brief to append h264 frame bits with the eopic bits
     * @param[out] bufSize size of input buffer allocated by MediaCodec of (type <tt>size_t</tt>)
     * @param[out] bufId id of the input buffer of (type <tt>size_t</tt>)
     * @return pointer to the input buffer, nullptr when failure
     */
    uint8_t *GetInputBuffer(size_t &bufSize, ssize_t &bufId) const;

    /*
     * @fn CheckSDKVersion
     * @brief to check if the sdn version is Android 7.0 or above
     * @return true if sdk version supported
     */
    bool CheckSDKVersion() const;

    int GetSDKVersion() const;

    bool ISHuaweiDevice() const;

    bool ISQcom() const;

    bool IsNeedAppendMockFrameBytes() const;

    bool IsStreamBeginFrame(const uint8_t *buf) const;

    uint64_t GetCurrentTimeMs() const;

    AMediaCodec *m_mediaCodec = nullptr;
    CasVideoUtil *m_casVideoUtil = nullptr;
    int m_sdkNo = 0;
    FrameType m_frameType = FrameType::H264;
    const char *m_mimeType;
    bool m_isHuawei = false;
    bool m_isQcom = false;
    uint32_t m_outputFrameCount = 0;
    uint32_t m_inputFrameCount = 0;
    bool m_isStreamBeginFrame = false;
    bool m_isDropFrame = false;
};

#endif // CLOUDAPPSDK_CASDECODER_H